#include "bsp_epd_ssd1677.h"
#include "driver/gpio.h"
#include <string.h>
#include "sw_spi.h" 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#define SW_SPI 0
#define HW_SPI 1
#define SPI_TYPE HW_SPI

// 定义 SPI 引脚（使用 SPI2/HSPI）
#define HSPI_MOSI 11 
#define HSPI_MISO 13
#define HSPI_SCLK 12                                                                                                        
#define HSPI_CS   10

#define EPD_DC   9
#define EPD_RST  8
#define EPD_BUSY 7

#define SPI_CS_1()      gpio_set_level(HSPI_CS, 1)
#define SPI_CS_0()      gpio_set_level(HSPI_CS, 0)

#define SPI_SCK_1()     gpio_set_level(HSPI_SCLK, 1)
#define SPI_SCK_0()     gpio_set_level(HSPI_SCLK, 0)

#define SPI_SDO_1()     gpio_set_level(HSPI_MOSI, 1)
#define SPI_SDO_0()     gpio_set_level(HSPI_MOSI, 0)

#define SPI_SDI_READ()  gpio_get_level(HSPI_MISO) // 读取SDI引脚的值

#define EPD_DC_1()      gpio_set_level(EPD_DC, 1)
#define EPD_DC_0()      gpio_set_level(EPD_DC, 0)

#define EPD_RST_1()      gpio_set_level(EPD_RST, 1)
#define EPD_RST_0()      gpio_set_level(EPD_RST, 0)

#define EPD_BUSY_READ()  gpio_get_level(EPD_BUSY) // 读取BUSY引脚的值



static void SPI_SDO_LOW(void);
static void SPI_SDO_HIGH(void);
static void SPI_SCK_LOW(void);
static void SPI_SCK_HIGH(void);
static uint8_t SPI_SDI_READ_LEVEL(void);
static void SPI_CS_LOW(void);
static void SPI_CS_HIGH(void);
static void SPI_Delay(uint32_t us);

static sw_spi_dev_t spi_epd_dev;
static sw_spi_msg_t spi_epd_msg;
#define DATA_BUF_SIZE 10
static uint8_t data_buf[DATA_BUF_SIZE];

/*The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. */
typedef struct {
    uint8_t cmd;
    uint8_t data[16];
    uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
} lcd_init_cmd_t;

static const uint8_t lut_1Gray_GC[] =
{
0x2A,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//1
0x05,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//2
0x2A,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//3
0x05,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//4
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//5
0x00,0x02,0x03,0x0A,0x00,0x02,0x06,0x0A,0x05,0x00,//6
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//7
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//8
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//9
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//10
0x22,0x22,0x22,0x22,0x22
};  

static const uint8_t lut_1Gray_DU[] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//1
0x01,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0A,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//3
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//5
0x00,0x00,0x05,0x05,0x00,0x05,0x03,0x05,0x05,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//7
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//9
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x22,0x22,0x22,0x22,0x22
}; 

static const uint8_t lut_1Gray_A2[] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //1
0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //2
0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //3
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //4
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //5
0x00,0x00,0x03,0x05,0x00,0x00,0x00,0x00,0x00,0x00, //6
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //7
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //8
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //9
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //10
0x22,0x22,0x22,0x22,0x22
}; 


#define Adjust 16
static void HAL_Delay_us(uint32_t us, uint16_t CLK_MHz )
{
    uint32_t Delay = us * CLK_MHz / Adjust;
    do
    {
        __asm__ __volatile__ ("nop");
    } while (Delay --);
}

static void HAL_Delay_ms()
{
    HAL_Delay_us(1000,240);
}

void epd_delay(uint32_t ms)
{
    for(uint32_t i = 0;i < ms;i++)
    {
        HAL_Delay_ms();
    }
}


void epd_gpio_config(void)
{
    // MOSI 配置为输出
    gpio_reset_pin(HSPI_MOSI);
    gpio_set_direction(HSPI_MOSI, GPIO_MODE_OUTPUT);
    gpio_set_level(HSPI_MOSI, 0); 
    // MISO 配置为输入（带上拉防止悬空）
    gpio_reset_pin(HSPI_MISO);
    gpio_set_direction(HSPI_MISO, GPIO_MODE_INPUT);
    gpio_set_pull_mode(HSPI_MISO, GPIO_PULLUP_ONLY);
    // SCLK 配置为输出
    gpio_reset_pin(HSPI_SCLK);
    gpio_set_direction(HSPI_SCLK, GPIO_MODE_OUTPUT);
    gpio_set_level(HSPI_SCLK, 0);
    // CS 配置为输出（可选）
    gpio_reset_pin(HSPI_CS);
    gpio_set_direction(HSPI_CS, GPIO_MODE_OUTPUT);
    gpio_set_level(HSPI_CS, 1); 
    // RS 配置为输出
    gpio_reset_pin(EPD_DC);
    gpio_set_direction(EPD_DC, GPIO_MODE_OUTPUT);
    gpio_set_level(EPD_DC, 0);  
    // RST 配置为输出
    gpio_reset_pin(EPD_RST);
    gpio_set_direction(EPD_RST, GPIO_MODE_OUTPUT);
    gpio_set_level(EPD_RST, 0);
    // BUSY 配置为输入
    gpio_reset_pin(EPD_BUSY);
    gpio_set_direction(EPD_BUSY, GPIO_MODE_INPUT);
    gpio_set_pull_mode(EPD_BUSY, GPIO_PULLUP_ONLY);
    // 设置 GPIO 驱动能力（可选，提高速度）
    gpio_set_drive_capability(HSPI_SCLK, GPIO_DRIVE_CAP_3); // 最大驱动能力
}

void epd_wait_busy(void)
{
    uint8_t busy;
    do{
        busy = EPD_BUSY_READ();
        // printf("wait busy...\n");
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }while(busy);
    epd_delay(200);
}

/**
 * @brief  硬件复位
 */
void epd_hw_reset(void)
{
    EPD_RST_1();
    epd_delay(10);
    EPD_RST_0(); 
    epd_delay(3); 
    EPD_RST_1();
    epd_delay(10); 
}

/**
 * @brief  软件复位
 */
void epd_sw_reset(void)
{
    epd_write_cmd(0x12); 
    epd_delay(10);
}

void epd_load_lut(uint8_t lut)
{
    uint16_t i;
    epd_write_cmd(0x32); // Write LUT register
    for(i = 0; i < 105; i++)
    {
        if(lut == EPD_REF_MODE_GC)
            epd_write_data(lut_1Gray_GC[i]);
        else if(lut == EPD_REF_MODE_DU)
            epd_write_data(lut_1Gray_DU[i]);
        else if(lut == EPD_REF_MODE_A2)
            epd_write_data(lut_1Gray_A2[i]);
        else
            {;}

    }
}

void epd_1gray_init(void)
{
    int cmd = 0;
    lcd_init_cmd_t epd_init_cmds[] = {
        {0x01, {(EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256, 0x02}, 3}, // Driver Output control 
        {0x03, {0x00}, 1}, // Gate Driving voltage Control 00=20
        {0x04, {0x41, 0xA8, 0x32}, 3}, // Source Driving voltage Control, default
        {0x11, {0x03}, 1}, // Data Entry mode, 11 –Y increment, X increment [POR]
        {0x3C, {0x01}, 1}, // Border Waveform Control, default
        {0x0C, {0xAE, 0xC7, 0xC3, 0xC0, 0x80}, 5}, // Booster Soft-start Control, level 2
        {0x18, {0x80}, 1}, // Temperature Sensor Control
        {0x2C, {0x44}, 1}, // Write VCOM register
        {0x37, {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF}, 10}, // Write Register for Display Option
        {0x44, {0x00, 0x00, (EPD_HEIGHT-1)%256, (EPD_HEIGHT-1)/256}, 4}, // set Ram-X address start/end position  
        {0x45, {0x00, 0x00, (EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256}, 4}, // set Ram-Y address start/end position
        {0x4E, {0x00, 0x00}, 2}, // set RAM x address count to 0;
        {0x4F, {0x00, 0x00}, 2}, // set RAM y address count to 0X199;  
        {0x22, {0xCF}, 1},
        {0, {0}, 0xff}, 
    };
    // lcd_init_cmd_t epd_init_cmds[] = {
    //     {0x18, {0x80}, 1}, // 
    //     {0x0C, {0xAE, 0xC7, 0xC3, 0xC0, 0x80}, 5},
    //     {0x01, {(EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256, 0x02}, 3}, // Driver output control      
    //     {0x3C, {0x01}, 1}, // BorderWavefrom
    //     {0x11, {0x03}, 1}, // data entry mode    
    //     {0x44, {0x00, 0x00, (EPD_HEIGHT-1)%256, (EPD_HEIGHT-1)/256}, 4}, // set Ram-X address start/end position  
    //     {0x45, {0x00, 0x00, (EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256}, 4}, // set Ram-Y address start/end position
    //     {0x4E, {0x00, 0x00}, 2}, // set RAM x address count to 0;
    //     {0x4F, {0x00, 0x00}, 2}, // set RAM y address count to 0X199;  
    //     {0, {0}, 0xff}, 
    // };
    // HW RESET
    epd_hw_reset();
    // SW RESET
    epd_sw_reset();

    epd_write_cmd(0x46); // Auto Write RED RAM for Regular Pattern
    epd_write_data(0xF7);
    epd_wait_busy();
    epd_write_cmd(0x47); // Auto Write B/W RAM for Regular Pattern
    epd_write_data(0xF7);
    epd_wait_busy();

	while (epd_init_cmds[cmd].databytes!=0xff) {
		epd_write_cmd(epd_init_cmds[cmd].cmd);
		epd_write_multidata(epd_init_cmds[cmd].data, epd_init_cmds[cmd].databytes&0x1F);
		if (epd_init_cmds[cmd].databytes&0x80) {
			// epd_delay(1); // 延时
		}
		cmd++;
	}
    epd_wait_busy();
}

void epd_1gray_refresh(uint8_t mode)
{
    epd_load_lut(mode);
    epd_write_cmd(0x20); // Refresh Display
    epd_wait_busy();
}


// 1 auto 0 full
void epd_auto_refresh(uint8_t mode)
{
    static uint8_t refresh_cnt = 0;
    if(mode == 1)
    {
        refresh_cnt++;
        if(refresh_cnt > 10)
        {
            refresh_cnt = 0;
            epd_1gray_refresh(EPD_REF_MODE_GC); // 全刷
        }
        else
        {
            epd_1gray_refresh(EPD_REF_MODE_A2); // 局刷
        }
    }
    else
    {
        refresh_cnt = 0;
        epd_1gray_refresh(EPD_REF_MODE_GC); // 全刷
    }

}


void epd_1gray_clear(uint8_t mode)
{
    uint16_t i;
    uint16_t IMAGE_COUNTER = EPD_WIDTH * EPD_HEIGHT / 8;

    epd_write_cmd(0x4E);
    epd_write_data(0x00); 
    epd_write_data(0x00); 
    epd_write_cmd(0x4F);
    epd_write_data(0x00);
    epd_write_data(0x00); 

    epd_write_cmd(0x24);
    for (i = 0; i < IMAGE_COUNTER; i++)
    {
        epd_write_data(0xFF);
    }

    epd_1gray_refresh(mode);
}

void epd_1gray_clear_norefresh(void)
{
    uint16_t i;
    uint16_t IMAGE_COUNTER = EPD_WIDTH * EPD_HEIGHT / 8;

    epd_write_cmd(0x4E);
    epd_write_data(0x00); 
    epd_write_data(0x00); 
    epd_write_cmd(0x4F);
    epd_write_data(0x00);
    epd_write_data(0x00); 

    epd_write_cmd(0x24);
    for (i = 0; i < IMAGE_COUNTER; i++)
    {
        epd_write_data(0xFF);
    }
    epd_write_cmd(0x26);
    for (i = 0; i < IMAGE_COUNTER; i++)
    {
        epd_write_data(0xFF);
    }

}


void epd_1gray_clear_color(uint8_t mode, uint8_t color)
{
    uint16_t i;
    uint16_t IMAGE_COUNTER = EPD_WIDTH * EPD_HEIGHT / 8;

    epd_write_cmd(0x4E);
    epd_write_data(0x00); 
    epd_write_data(0x00); 
    epd_write_cmd(0x4F);
    epd_write_data(0x00);
    epd_write_data(0x00); 

    epd_write_cmd(0x24);
    for (i = 0; i < IMAGE_COUNTER; i++)
    {
        epd_write_data(color);
    }

    epd_1gray_refresh(mode);
}



void epd_1gray_display_all(const uint8_t *image,uint8_t mode)
{
    uint16_t i;
    uint16_t IMAGE_COUNTER = EPD_WIDTH * EPD_HEIGHT / 8;

    epd_write_cmd(0x4E);
    epd_write_data(0x00); 
    epd_write_data(0x00); 
    epd_write_cmd(0x4F);
    epd_write_data(0x00);
    epd_write_data(0x00); 

    epd_write_cmd(0x24);
    // for (i = 0; i < IMAGE_COUNTER; i++)
    // {
    //     epd_write_data(image[i]);
    // }
    epd_write_multidata(image, IMAGE_COUNTER);
    epd_1gray_refresh(mode);
}



void epd_1gray_display_part(const uint8_t *image, uint16_t x_start,uint16_t y_start,uint16_t x_end,uint16_t y_end)
{
    uint16_t i, Width;
    Width = (x_end-x_start)%8 == 0 ? (x_end-x_start)/8 : (x_end-x_start)/8+1;
    uint16_t IMAGE_COUNTER = Width * (y_end-y_start);

    epd_write_cmd(0x44);
    epd_write_data(x_start & 0xff);
    epd_write_data((x_start>>8) & 0x03);
    epd_write_data(x_end & 0xff);
    epd_write_data((x_end>>8) & 0x03);
    epd_write_cmd(0x45);
    epd_write_data(y_start & 0xff);
    epd_write_data((y_start>>8) & 0x03);
    epd_write_data(y_end & 0xff);
    epd_write_data((y_end>>8) & 0x03);

    epd_write_cmd(0x24);
    for (i = 0; i < IMAGE_COUNTER; i++)
    {
        epd_write_data(image[i]);
    }
    // epd_1gray_refresh(0);
}


void epd_1gray_display_part_icon(const uint8_t *image, uint16_t x_start,uint16_t y_start,uint16_t iwidth,uint16_t iheight)
{
    uint16_t i, j;
    unsigned int x_end,y_end;

    x_start=x_start-x_start%8; //x address start
	x_end=x_start+iheight-1; //x address end
	y_start=y_start; //Y address start
	y_end=y_start+iwidth-1; //Y address end

    epd_write_cmd(0x44);
    epd_write_data(x_start & 0xff);
    epd_write_data((x_start>>8) & 0x03);
    epd_write_data(x_end & 0xff);
    epd_write_data((x_end>>8) & 0x03);
    epd_write_cmd(0x45);
    epd_write_data(y_start & 0xff);
    epd_write_data((y_start>>8) & 0x03);
    epd_write_data(y_end & 0xff);
    epd_write_data((y_end>>8) & 0x03);

	epd_write_cmd(0x4E);        // set RAM x address count to 0;
	epd_write_data(x_start%256);  //x address start2
	epd_write_data(x_start/256); //x address start1
	epd_write_cmd(0x4F);      // set RAM y address count to 0X127;
	epd_write_data(y_start%256);//y address start2
	epd_write_data(y_start/256);//y address start1

    epd_write_cmd(0x24);
    for (i = 0; i < iwidth*iheight/8; i++)
    {
        epd_write_data(image[i]);
    }

}

void epd_1gray_display_part_icon_edge(const uint8_t *image, uint16_t x_start,uint16_t y_start,uint16_t iwidth,uint16_t iheight)
{
    uint16_t i, j;
    unsigned int x_end,y_end;

    x_start=x_start-x_start%8; //x address start
	x_end=x_start+iheight-1; //x address end
	y_start=y_start; //Y address start
	y_end=y_start+iwidth-1; //Y address end

    epd_write_cmd(0x44);
    epd_write_data(x_start & 0xff);
    epd_write_data((x_start>>8) & 0x03);
    epd_write_data(x_end & 0xff);
    epd_write_data((x_end>>8) & 0x03);
    epd_write_cmd(0x45);
    epd_write_data(y_start & 0xff);
    epd_write_data((y_start>>8) & 0x03);
    epd_write_data(y_end & 0xff);
    epd_write_data((y_end>>8) & 0x03);

	epd_write_cmd(0x4E);        // set RAM x address count to 0;
	epd_write_data(x_start%256);  //x address start2
	epd_write_data(x_start/256); //x address start1
	epd_write_cmd(0x4F);      // set RAM y address count to 0X127;
	epd_write_data(y_start%256);//y address start2
	epd_write_data(y_start/256);//y address start1

    epd_write_cmd(0x24);
    for(i = 0;i < iwidth; i++)
    {
        for(j = 0;j < iheight/8;j++)
        {
            // 左边和右边
            if(i == 0 || i == 1|| (i == iwidth-2) || (i == iwidth-1))
            {
                epd_write_data(0x00);
            }
            else
            {
                // 上边和下边
                if((j == 0))
                {
                    epd_write_data(image[i*iheight/8+j] & 0x3F);

                }
                else if(j == iheight/8-1)
                {
                    epd_write_data(image[i*iheight/8+j] & 0xFC);

                }
                else
                {
                    epd_write_data(image[i*iheight/8+j]);
                }
            }
            
        }
    }


}

// 此函数在SPI传输开始之前被调用（在irq上下文中！），通过用户字段的值来设置D/C信号线
void lcd_spi_pre_transfer_callback(spi_transaction_t *t)
{
	int dc = (int)t->user;
    if(dc > 0)
	    gpio_set_level(EPD_DC, 1);
    else 
        gpio_set_level(EPD_DC, 0);
    
}

#define EPD_HOST	SPI2_HOST // ESP32-S3的SPI2主机
#define DMA_CHAN		1

spi_device_handle_t spi_handle;

void bsp_epd_init(void)
{

#if SPI_TYPE == SW_SPI
    epd_gpio_config();

    spi_epd_dev.name = "spi_epd";
    spi_epd_dev.speed = 2;
    spi_epd_dev.mode = SPI_MODE_1;
    spi_epd_dev.bit_order = SPI_MSB_FIRST;
    spi_epd_dev.delay_us = SPI_Delay;
    spi_epd_dev.ops.sdo_low = SPI_SDO_LOW;
    spi_epd_dev.ops.sdo_high = SPI_SDO_HIGH;
    spi_epd_dev.ops.sck_low = SPI_SCK_LOW;
    spi_epd_dev.ops.sck_high = SPI_SCK_HIGH;
    spi_epd_dev.ops.sdi_read_level = SPI_SDI_READ_LEVEL;
    spi_epd_dev.ops.cs_low = SPI_CS_LOW;
    spi_epd_dev.ops.cs_high = SPI_CS_HIGH;
    sw_spi_init(&spi_epd_dev);
    spi_epd_msg.buf = data_buf;
#elif SPI_TYPE == HW_SPI
    esp_err_t ret;
    // SPI总线配置
    spi_bus_config_t buscfg = {
        .miso_io_num = -1,
        .mosi_io_num = HSPI_MOSI,
        .sclk_io_num = HSPI_SCLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = EPD_WIDTH * EPD_HEIGHT/8
    };
    // SPI驱动接口配置
    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 10 * 1000 * 1000,				// SPI时钟 30 MHz
        .mode = 0,									// SPI模式0
        .spics_io_num = HSPI_CS,					// CS片选信号引脚
        .queue_size = 7,							// 事务队列尺寸 7个
        .pre_cb = NULL,	// 数据传输前回调，用作D/C（数据命令）线分别处理
        .post_cb = NULL
    };
	// 初始化SPI总线
	ret=spi_bus_initialize(EPD_HOST, &buscfg, SPI_DMA_CH_AUTO);
	ESP_ERROR_CHECK(ret);
	// 添加SPI总线驱动
	ret=spi_bus_add_device(EPD_HOST, &devcfg, &spi_handle);
	ESP_ERROR_CHECK(ret);
    // RS 配置为输出
    gpio_reset_pin(EPD_DC);
    gpio_set_direction(EPD_DC, GPIO_MODE_OUTPUT);
    gpio_set_level(EPD_DC, 0);  
    // RST 配置为输出
    gpio_reset_pin(EPD_RST);
    gpio_set_direction(EPD_RST, GPIO_MODE_OUTPUT);
    gpio_set_level(EPD_RST, 0);
    // BUSY 配置为输入
    gpio_reset_pin(EPD_BUSY);
    gpio_set_direction(EPD_BUSY, GPIO_MODE_INPUT);
    gpio_set_pull_mode(EPD_BUSY, GPIO_PULLUP_ONLY);

#endif
}


portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
void epd_write_cmd(uint8_t cmd)
{
#if SPI_TYPE == SW_SPI
    EPD_DC_0(); // 选择命令模式
    spi_epd_msg.len = 1;
    spi_epd_msg.buf[0] = cmd;
    sw_spi_transfer(&spi_epd_dev, &spi_epd_msg);
    EPD_DC_1(); // 选择数据模式
#elif SPI_TYPE == HW_SPI
    esp_err_t ret;
    spi_transaction_t t;
	memset(&t, 0, sizeof(spi_transaction_t));		// 清空结构体
	t.length = 8;						// 要传输的位数 一个字节 8位
	t.tx_buffer = &cmd;				// 将命令填充进去
	// t.user = (void*)0;				// 设置D/C 线，在SPI传输前回调中根据此值处理DC信号线
    EPD_DC_0(); // 选择命令模式
	ret = spi_device_polling_transmit(spi_handle, &t);		// 开始传输
    EPD_DC_1(); // 选择数据模式
	assert(ret == ESP_OK);			// 一般不会有问题
    
#endif
}

void epd_write_data(uint8_t data)
{
#if SPI_TYPE == SW_SPI
    spi_epd_msg.len = 1;
    spi_epd_msg.buf[0] = data;
    sw_spi_transfer(&spi_epd_dev, &spi_epd_msg);
#elif SPI_TYPE == HW_SPI
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(spi_transaction_t));		// 清空结构体
    t.length = 8;					// 要写入的数据长度 Len 是字节数，len, transaction length is in bits.
    t.tx_buffer = &data;				// 数据指针
    // t.user = (void*)1;				// 设置D/C 线，在SPI传输前回调中根据此值处理DC信号线
    ret = spi_device_polling_transmit(spi_handle, &t);		// 开始传输
    assert(ret == ESP_OK);			// 一般不会有问题

#endif
}

void epd_write_multidata(uint8_t *pdata, uint16_t len)
{
#if SPI_TYPE == SW_SPI
    spi_epd_msg.len = len;
    // spi_epd_msg.buf = pdata;
    memcpy(spi_epd_msg.buf, pdata, len);
    sw_spi_transfer(&spi_epd_dev, &spi_epd_msg);
    spi_epd_msg.buf = data_buf;
#elif SPI_TYPE == HW_SPI
    const uint32_t MAX_SPI_LEN = 4092; // ESP32-S3单次SPI传输最大值    
    uint32_t sent = 0;
    esp_err_t ret;
    spi_transaction_t t;
    if(len == 0) return;				// 长度为0 没有数据要传输

    while (len > 0) {
            uint32_t chunk_size = (len > MAX_SPI_LEN) ? MAX_SPI_LEN : len;
            spi_transaction_t t = {
                .length = chunk_size * 8,
                .tx_buffer = pdata + sent,
                // .user = (void*)1, // DC=1
            };
            ret = spi_device_polling_transmit(spi_handle, &t);		// 开始传输
            assert(ret == ESP_OK);			// 一般不会有问题
            len -= chunk_size;
            sent += chunk_size;
    }
#if 0
    esp_err_t ret;
    spi_transaction_t t;
    if(len == 0) return;				// 长度为0 没有数据要传输
    memset(&t, 0, sizeof(spi_transaction_t));		// 清空结构体
    t.length = len * 8;					// 要写入的数据长度 Len 是字节数，len, transaction length is in bits.
    t.tx_buffer = pdata;				// 数据指针
    // t.user = (void*)1;				// 设置D/C 线，在SPI传输前回调中根据此值处理DC信号线
    ret = spi_device_polling_transmit(spi_handle, &t);		// 开始传输
    assert(ret == ESP_OK);			// 一般不会有问题
#endif
#endif
}
// 全屏刷新更新功能
void epd_update(void)
{
    epd_write_cmd(0x22);
    epd_write_data(0xF7);
    epd_write_cmd(0x20);
    epd_wait_busy();
}

// 快速刷新更新功能
void epd_fast_update(void)
{
    epd_write_cmd(0x22);
    epd_write_data(0xC7);
    epd_write_cmd(0x20);
    epd_wait_busy();
}

// 部分刷新更新功能
void epd_part_update(void)
{
    epd_write_cmd(0x22);
    epd_write_data(0xFF);
    epd_write_cmd(0x20);
    epd_wait_busy();
}

void epd_clear_black(void)
{
    epd_write_cmd(0x24);
    for (int i = 0; i < EPD_SCREEN_SIZE; i++) {
        epd_write_data(0x00); // 黑色
    }
    epd_update();
}

void epd_clear_white(void)
{
    epd_write_cmd(0x24);
    for (int i = 0; i < EPD_SCREEN_SIZE; i++) {
        epd_write_data(0xFF); // 白色
    }
    epd_update();
}

void epd_write_image(uint8_t *image)
{
	unsigned int Width, Height,i,j;
	Width = (EPD_WIDTH % 8 == 0)? (EPD_WIDTH / 8 ): (EPD_WIDTH / 8 + 1);
	Height = EPD_HEIGHT;

	epd_write_cmd(0x24);
	for ( j = 0; j < Height; j++) {
			for ( i = 0; i < Width; i++) {
				 epd_write_data(image[i + j * Width]);
			}
	}
	epd_update();
}

void epd_write_image_fast(uint8_t *image)
{
	unsigned int Width, Height,i,j;
	Width = (EPD_WIDTH % 8 == 0)? (EPD_WIDTH / 8 ): (EPD_WIDTH / 8 + 1);
	Height = EPD_HEIGHT;

	epd_write_cmd(0x24);
	for ( j = 0; j < Height; j++) {
			for ( i = 0; i < Width; i++) {
				 epd_write_data(image[i + j * Width]);
			}
	}
	epd_fast_update();
}
void epd_write_image_part_all(uint8_t *image)
{
	unsigned int i;  
	unsigned int PART_COLUMN, PART_LINE;
	PART_COLUMN=EPD_HEIGHT,PART_LINE=EPD_WIDTH;

    //Reset
	EPD_RST_0();  // Module reset
	epd_delay(10);//At least 10ms delay
	EPD_RST_1();
	epd_delay(10); //At least 10ms delay

	epd_write_cmd(0x18); 
	epd_write_data(0x80);

	epd_write_cmd(0x3C); //BorderWavefrom  
	epd_write_data(0x80);
	
	epd_write_cmd(0x24);   //Write Black and White image to RAM
	for(i=0;i<PART_COLUMN*PART_LINE/8;i++)
	{                         
		epd_write_data(image[i]);
	} 
	epd_part_update();
}

void epd_write_image_part(uint32_t x_start,uint32_t y_start,const uint8_t * datas,uint32_t PART_COLUMN,uint32_t PART_LINE)
{
    unsigned int i;  
	unsigned int x_end,y_end;
	
	x_start=x_start-x_start%8; //x address start
	x_end=x_start+PART_LINE-1; //x address end
	y_start=y_start; //Y address start
	y_end=y_start+PART_COLUMN-1; //Y address end

    //Reset
	EPD_RST_0();  // Module reset
	epd_delay(10);//At least 10ms delay
	EPD_RST_1();
	epd_delay(10); //At least 10ms delay

	epd_write_cmd(0x18); 
	epd_write_data(0x80);

	epd_write_cmd(0x3C); //BorderWavefrom  
	epd_write_data(0x80);	

	epd_write_cmd(0x44);       // set RAM x address start/end
	epd_write_data(x_start%256);  //x address start2 
	epd_write_data(x_start/256); //x address start1 
	epd_write_data(x_end%256);  //x address end2 
	epd_write_data(x_end/256); //x address end1   
	epd_write_cmd(0x45);    // set RAM y address start/end
	epd_write_data(y_start%256);  //y address start2 
	epd_write_data(y_start/256); //y address start1 
	epd_write_data(y_end%256);  //y address end2 
	epd_write_data(y_end/256); //y address end1   

	epd_write_cmd(0x4E);        // set RAM x address count to 0;
	epd_write_data(x_start%256);  //x address start2
	epd_write_data(x_start/256); //x address start1
	epd_write_cmd(0x4F);      // set RAM y address count to 0X127;
	epd_write_data(y_start%256);//y address start2
	epd_write_data(y_start/256);//y address start1

	epd_write_cmd(0x24);   //Write Black and White image to RAM
    for(i=0;i < PART_COLUMN*PART_LINE/8;i++)
    {
		epd_write_data(datas[i]);
    }
    
}

void epd_write_image_edge_part(uint32_t x_start,uint32_t y_start,const uint8_t * datas,uint32_t PART_COLUMN,uint32_t PART_LINE)
{
    unsigned int i,j;  
	unsigned int x_end,y_end;
	
	x_start=x_start-x_start%8; //x address start
	x_end=x_start+PART_LINE-1; //x address end
	y_start=y_start; //Y address start
	y_end=y_start+PART_COLUMN-1; //Y address end

    //Reset
	EPD_RST_0();  // Module reset
	epd_delay(10);//At least 10ms delay
	EPD_RST_1();
	epd_delay(10); //At least 10ms delay

	epd_write_cmd(0x18); 
	epd_write_data(0x80);

	epd_write_cmd(0x3C); //BorderWavefrom  
	epd_write_data(0x80);	

	epd_write_cmd(0x44);       // set RAM x address start/end
	epd_write_data(x_start%256);  //x address start2 
	epd_write_data(x_start/256); //x address start1 
	epd_write_data(x_end%256);  //x address end2 
	epd_write_data(x_end/256); //x address end1   
	epd_write_cmd(0x45);    // set RAM y address start/end
	epd_write_data(y_start%256);  //y address start2 
	epd_write_data(y_start/256); //y address start1 
	epd_write_data(y_end%256);  //y address end2 
	epd_write_data(y_end/256); //y address end1   

	epd_write_cmd(0x4E);        // set RAM x address count to 0;
	epd_write_data(x_start%256);  //x address start2
	epd_write_data(x_start/256); //x address start1
	epd_write_cmd(0x4F);      // set RAM y address count to 0X127;
	epd_write_data(y_start%256);//y address start2
	epd_write_data(y_start/256);//y address start1

	epd_write_cmd(0x24);   //Write Black and White image to RAM
    for(i = 0;i < PART_COLUMN; i++)
    {
        for(j = 0;j < PART_LINE/8;j++)
        {
            // 左边和右边
            if(i == 0 || i == 1|| (i == PART_COLUMN-2) || (i == PART_COLUMN-1))
            {
                epd_write_data(0x00);
            }
            else
            {
                // 上边和下边
                if((j == 0))
                {
                    epd_write_data(datas[i*PART_LINE/8+j] & 0x3F);

                }
                else if(j == PART_LINE/8-1)
                {
                    epd_write_data(datas[i*PART_LINE/8+j] & 0xFC);

                }
                else
                {
                    epd_write_data(datas[i*PART_LINE/8+j]);
                }
            }
            
        }
    }
}

void epd_clear_part(uint32_t x_start,uint32_t y_start, uint8_t color, uint32_t PART_COLUMN,uint32_t PART_LINE)
{
    unsigned int i;  
	unsigned int x_end,y_end;
	
	x_start=x_start-x_start%8; //x address start
	x_end=x_start+PART_LINE-1; //x address end
	y_start=y_start; //Y address start
	y_end=y_start+PART_COLUMN-1; //Y address end

    //Reset
	EPD_RST_0();  // Module reset
	epd_delay(10);//At least 10ms delay
	EPD_RST_1();
	epd_delay(10); //At least 10ms delay

	epd_write_cmd(0x18); 
	epd_write_data(0x80);

	epd_write_cmd(0x3C); //BorderWavefrom  
	epd_write_data(0x80);	

	epd_write_cmd(0x44);       // set RAM x address start/end
	epd_write_data(x_start%256);  //x address start2 
	epd_write_data(x_start/256); //x address start1 
	epd_write_data(x_end%256);  //x address end2 
	epd_write_data(x_end/256); //x address end1   
	epd_write_cmd(0x45);    // set RAM y address start/end
	epd_write_data(y_start%256);  //y address start2 
	epd_write_data(y_start/256); //y address start1 
	epd_write_data(y_end%256);  //y address end2 
	epd_write_data(y_end/256); //y address end1   

	epd_write_cmd(0x4E);        // set RAM x address count to 0;
	epd_write_data(x_start%256);  //x address start2
	epd_write_data(x_start/256); //x address start1
	epd_write_cmd(0x4F);      // set RAM y address count to 0X127;
	epd_write_data(y_start%256);//y address start2
	epd_write_data(y_start/256);//y address start1

	epd_write_cmd(0x24);   //Write Black and White image to RAM
    for(i=0;i < PART_COLUMN*PART_LINE/8;i++)
    {
		epd_write_data(color);
    }
    epd_part_update();
}



/*
* Deep Sleep mode 
* 00 Normal Mode [POR]
* 11 Enter Deep Sleep Mode
* After this command initiated, the chip will enter Deep Sleep Mode, BUSY pad will
* keep output high.
* Remark: To Exit Deep Sleep mode, User required to send HWRESET to the driver 
* HWRESET = RST PIN
*/
void epd_deep_sleep(void)
{
    epd_write_cmd(0x10);
    epd_write_data(0x03);
}


// GD驱动 gooddisplay
void epd_gd_hw_init(void)
{
    int cmd = 0;
    lcd_init_cmd_t epd_init_cmds[] = {
        {0x18, {0x80}, 1}, // 
        {0x0C, {0xAE, 0xC7, 0xC3, 0xC0, 0x80}, 5},
        {0x01, {(EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256, 0x02}, 3}, // Driver output control      
        {0x3C, {0x01}, 1}, // BorderWavefrom
        {0x11, {0x03}, 1}, // data entry mode    
        {0x44, {0x00, 0x00, (EPD_HEIGHT-1)%256, (EPD_HEIGHT-1)/256}, 4}, // set Ram-X address start/end position  
        {0x45, {0x00, 0x00, (EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256}, 4}, // set Ram-Y address start/end position
        {0x4E, {0x00, 0x00}, 2}, // set RAM x address count to 0;
        {0x4F, {0x00, 0x00}, 2}, // set RAM y address count to 0X199;  
        {0, {0}, 0xff}, 
    };
    // HW RESET
    epd_hw_reset();
    // SW RESET
    epd_sw_reset();

	while (epd_init_cmds[cmd].databytes!=0xff) {
		epd_write_cmd(epd_init_cmds[cmd].cmd);
		epd_write_multidata(epd_init_cmds[cmd].data, epd_init_cmds[cmd].databytes&0x1F);
		if (epd_init_cmds[cmd].databytes&0x80) {
			epd_delay(1); // 延时
		}
		cmd++;
	}
    epd_wait_busy();
}
void epd_gd_hw_init_fast(void)
{
    int cmd = 0;
    lcd_init_cmd_t epd_init_cmds[] = {
        {0x18, {0x80}, 1}, // 
        {0x0C, {0xAE, 0xC7, 0xC3, 0xC0, 0x80}, 5},
        {0x01, {(EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256, 0x02}, 3}, // Driver output control      
        {0x3C, {0x01}, 1}, // BorderWavefrom
        {0x11, {0x03}, 1}, // data entry mode    
        {0x44, {0x00, 0x00, (EPD_HEIGHT-1)%256, (EPD_HEIGHT-1)/256}, 4}, // set Ram-X address start/end position  
        {0x45, {0x00, 0x00, (EPD_WIDTH-1)%256, (EPD_WIDTH-1)/256}, 4}, // set Ram-Y address start/end position
        {0x4E, {0x00, 0x00}, 2}, // set RAM x address count to 0;
        {0x4F, {0x00, 0x00}, 2}, // set RAM y address count to 0X199;  
        {0x1A, {0x5A}, 1},
        {0, {0}, 0xff}, 
    };
    // HW RESET
    epd_hw_reset();
    // SW RESET
    epd_sw_reset();
    
	while (epd_init_cmds[cmd].databytes!=0xff) {
		epd_write_cmd(epd_init_cmds[cmd].cmd);
		epd_write_multidata(epd_init_cmds[cmd].data, epd_init_cmds[cmd].databytes&0x1F);
		if (epd_init_cmds[cmd].databytes&0x80) {
			epd_delay(1); // 延时
		}
		cmd++;
	}

    epd_write_cmd(0x22);
    epd_write_data(0x91);
    epd_write_cmd(0x20);

    epd_wait_busy();
}
void epd_gd_update(void)
{
    epd_write_cmd(0x22);
    epd_write_data(0xF7);
    epd_write_cmd(0x20);
    epd_wait_busy();
}
void epd_gd_update_fast(void)
{
    epd_write_cmd(0x22);
    epd_write_data(0xC7);
    epd_write_cmd(0x20);
    epd_wait_busy();
}
void epd_gd_part_update(void)
{
    epd_write_cmd(0x22);
    epd_write_data(0xFF);
    epd_write_cmd(0x20);
    epd_wait_busy();
}
void epd_gd_writescreen_all(const unsigned char *datas)
{
    unsigned int i;	
    epd_write_cmd(0x24);   //write RAM for black(0)/white (1)
    for(i=0;i < EPD_SCREEN_SIZE;i++)
    {               
        epd_write_data(datas[i]);
    }	 
    epd_gd_update();	 
}
void epd_gd_writescreen_all_fast(const unsigned char *datas)
{
    unsigned int i;	
    epd_write_cmd(0x24);   //write RAM for black(0)/white (1)
    for(i=0;i<EPD_SCREEN_SIZE;i++)
    {               
        epd_write_data(datas[i]);
    }  	 
    epd_gd_update_fast();	 
}
void epd_gd_writescreen_white(void)
{
    unsigned int i;
    epd_write_cmd(0x24);   //write RAM for black(0)/white (1)
    for(i=0;i<EPD_SCREEN_SIZE;i++)
    {
        epd_write_data(0xff);
    }
    epd_gd_update();
}
void epd_gd_writescreen_black(void)
{
    unsigned int i;
    epd_write_cmd(0x24);   //write RAM for black(0)/white (1)
    for(i=0;i<EPD_SCREEN_SIZE;i++)
    {
        epd_write_data(0x00);
    }
    epd_gd_update();
}
void epd_gd_setramvalue_basemap(const unsigned char * datas)
{
    unsigned int i;   	
    epd_write_cmd(0x24);   //Write Black and White image to RAM
    for(i=0;i<EPD_SCREEN_SIZE;i++)
    {               
        epd_write_data(datas[i]);
    }

    epd_write_cmd(0x26);   //Write Black and White image to RAM
    for(i=0;i<EPD_SCREEN_SIZE;i++)
    {               
        epd_write_data(datas[i]);
    }
    epd_gd_update();	
}
void epd_gd_dis_part(unsigned int x_start,unsigned int y_start,const unsigned char * datas,unsigned int PART_COLUMN,unsigned int PART_LINE)
{
	unsigned int i;  
	unsigned int x_end,y_end;
	
	x_start=x_start-x_start%8; //x address start
	x_end=x_start+PART_LINE-1; //x address end
	y_start=y_start; //Y address start
	y_end=y_start+PART_COLUMN-1; //Y address end
	
    epd_hw_reset();

	epd_write_cmd(0x18); 
	epd_write_data(0x80);
	
	epd_write_cmd(0x3C); //BorderWavefrom  
	epd_write_data(0x80);	

	epd_write_cmd(0x44);       // set RAM x address start/end
	epd_write_data(x_start%256);  //x address start2 
	epd_write_data(x_start/256); //x address start1 
	epd_write_data(x_end%256);  //x address end2 
	epd_write_data(x_end/256); //x address end1   
	epd_write_cmd(0x45);    // set RAM y address start/end
	epd_write_data(y_start%256);  //y address start2 
	epd_write_data(y_start/256); //y address start1 
	epd_write_data(y_end%256);  //y address end2 
	epd_write_data(y_end/256); //y address end1   

	epd_write_cmd(0x4E);        // set RAM x address count to 0;
	epd_write_data(x_start%256);  //x address start2
	epd_write_data(x_start/256); //x address start1
	epd_write_cmd(0x4F);      // set RAM y address count to 0X127;
	epd_write_data(y_start%256);//y address start2
	epd_write_data(y_start/256);//y address start1

    epd_write_cmd(0x24);   //write RAM for black(0)/white (1)
    for(i=0;i<PART_COLUMN*PART_LINE/8;i++)
    {               
        epd_write_data(datas[i]);
    }  	 
    epd_gd_update();	 

}
void epd_gd_dis_partall(const unsigned char * datas)
{
	unsigned int i;  
	unsigned int PART_COLUMN, PART_LINE;
	PART_COLUMN=EPD_HEIGHT,PART_LINE=EPD_WIDTH;

    epd_hw_reset();
	epd_write_cmd(0x18); 
	epd_write_data(0x80);
	
	epd_write_cmd(0x3C); //BorderWavefrom  
	epd_write_data(0x80);	

    epd_write_cmd(0x24);   //write RAM for black(0)/white (1)
    for(i=0;i<PART_COLUMN*PART_LINE/8;i++)
    {               
        epd_write_data(datas[i]);
    }  	 
    epd_gd_update();	 

}
void epd_gd_deepsleep(void)
{
    epd_write_cmd(0x10);
    epd_write_data(0x01);
    epd_delay(100);
}
void epd_gd_dis_part_ram(unsigned int x_start,unsigned int y_start,const unsigned char * datas,unsigned int PART_COLUMN,unsigned int PART_LINE)
{
	unsigned int i;  
	unsigned int x_end,y_end;
	
	x_start=x_start-x_start%8; //x address start
	x_end=x_start+PART_LINE-1; //x address end
	y_start=y_start; //Y address start
	y_end=y_start+PART_COLUMN-1; //Y address end
	
    epd_hw_reset();

	epd_write_cmd(0x18); 
	epd_write_data(0x80);
	
	epd_write_cmd(0x3C); //BorderWavefrom  
	epd_write_data(0x80);	

	epd_write_cmd(0x44);       // set RAM x address start/end
	epd_write_data(x_start%256);  //x address start2 
	epd_write_data(x_start/256); //x address start1 
	epd_write_data(x_end%256);  //x address end2 
	epd_write_data(x_end/256); //x address end1   
	epd_write_cmd(0x45);    // set RAM y address start/end
	epd_write_data(y_start%256);  //y address start2 
	epd_write_data(y_start/256); //y address start1 
	epd_write_data(y_end%256);  //y address end2 
	epd_write_data(y_end/256); //y address end1   

	epd_write_cmd(0x4E);        // set RAM x address count to 0;
	epd_write_data(x_start%256);  //x address start2
	epd_write_data(x_start/256); //x address start1
	epd_write_cmd(0x4F);      // set RAM y address count to 0X127;
	epd_write_data(y_start%256);//y address start2
	epd_write_data(y_start/256);//y address start1

    epd_write_cmd(0x24);   //write RAM for black(0)/white (1)
    for(i=0;i<PART_COLUMN*PART_LINE/8;i++)
    {               
        epd_write_data(datas[i]);
    }  	 
 
}
void epd_gd_hw_init_180(void)
{

}
void epd_gd_hw_init_gui(void)
{

}




/********************************************************************************************************/


static void SPI_SDO_LOW(void)
{
    SPI_SDO_0();
}

static void SPI_SDO_HIGH(void)
{
    SPI_SDO_1();
}

static void SPI_SCK_LOW(void)
{
    SPI_SCK_0();
}

static void SPI_SCK_HIGH(void)
{
    SPI_SCK_1();
}

static uint8_t SPI_SDI_READ_LEVEL(void)
{
    return SPI_SDI_READ();
}

static void SPI_CS_LOW(void)
{
    SPI_CS_0();
}
static void SPI_CS_HIGH(void)
{
    SPI_CS_1();
}

static void SPI_Delay(uint32_t us)
{
    HAL_Delay_us(us, 240);
}
